// 我们使用Set数据结构作为存储副作用函数的‘桶’，导致上一节的根本原因是：我们没有在副作用函数和被操作目标字段之间建立明确的联系。
// 重新设计桶的数据结构
// effectFn(() => {
//   //   document.body.innerText = objProxy.text;
//   console.log("objProxy.text=", objProxy.text);
// });

// 分析上面的代码中有三个角色：
// 1. 被操作的代理对象 objProxy 【target】
// 2. 被操作的字段名 text       【key】
// 3. 副作用函数 effectFn       【effectFn】
// 三个角色的关系如下
/**
 * target
 *    -> key
 *        -> effectFn
 */

/** 1. 如果两个副作用函数同时读取一个对象属性值，那么关系如下
 * target
 *    -> key
 *        -> effectFn1
 *        -> effectFn2
 *
 */

/** 2. 如果一个副作用函数同时读取两个对象属性值，那么关系如下
 * target
 *    -> key1
 *        -> effectFn
 *    -> key2
 *        -> effectFn
 */

/** 3. 如果两个副作用函数分别读取两个对象属性值，那么关系如下
 * target
 *    -> key1
 *        -> effectFn1
 *     -> key2
 *        -> effectFn2
 */

// 如上这个属性结构的联系创建好之后就能解决上一节出现的问题。只有修改对应字段的值才会导致对应副作用函数重新执行，不会影响到其他副作用函数。

// 使用WeakMap代替Set数据结构的桶类型
const bucket = new WeakMap();
/**
 * target【WeakMap】由 target --> Map 构成
 *    -> key【Map】由 key --> Set 构成
 *        -> effectFn【Set】Set数据结构存储的副作用函数集合称为key的依赖集合
 */
function track(target, key) {
  if (!activeEffect) return target[key];
  let depsMap = bucket.get(target);
  if (!depsMap) {
    bucket.set(target, (depsMap = new Map()));
  }
  let deps = depsMap.get(key);
  if (!deps) {
    depsMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
}
function trigger(target, key) {
  const depsMap = bucket.get(target);
  if (!depsMap) return;

  const effects = depsMap.get(key);
  effects && effects.forEach((fn) => fn());
}

let activeEffect = undefined;
function effect(fn) {
  activeEffect = fn;
  fn();
}

const obj = { text: "hello" };
const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    track(target, key);
    return target[key];
  },
  set(target, key, val, receiver) {
    target[key] = val;
    trigger(target, key);
    return true;
  },
});

effect(() => {
  console.log("effect", objProxy.text);
});

setTimeout(() => {
  objProxy.text = "hello vue3";
}, 1000);
